<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        /*         function fn1() {
                    var a = 2;
                    function fn2() {
                        a--;
                        console.log(a);
                    }
                    return fn2;
                }
                var f = fn1();
                f();
                f(); */

        /*         function fn1(){
                    var a = 2;
                    a++;
                    console.log(a);
                }
                fn1();
                fn1(); */

        /*                 function outerFn() {
                            var i = 0;
                            function innerFn() {
                                i++;
                                console.log(i);
                            }
                            return innerFn;
                        }
                        var inner = outerFn();  //每次外部函数执行的时候,都会开辟一块内存空间,外部函数的地址不同，都会重新创建一个新的地址
                        var inner2 = outerFn();
                        inner();
                        inner2();
                        inner();
                        inner2();
                        inner();
                        inner2(); //1 1 2 2 3 3 */

        /*                 inner2();
                        inner2();
                        inner2();   //1 2 3 1 2 3 */

        /*                 var i = 0;
                        function outerFn() {
                            function innnerFn() {
                                i++;
                                console.log(i);
                            }
                            return innnerFn;
                        }
                        var inner1 = outerFn();
                        var inner2 = outerFn();
                        inner1();
                        inner2();
                        inner1();
                        inner2();     //1 2 3 4 */

        /*                 function outerFn(){
                            var i = 0;
                            function innnerFn(){
                                i++;
                                console.log(i);
                            }
                            return innnerFn;
                            }
                            var inner1 = outerFn();
                            var inner2 = outerFn();
                            inner1();
                            inner2();
                            inner1();
                            inner2();    //1 1 2 2      */


        /*         function fn() {
                    var a = 3;
                    return function () {
                        return ++a;
                    }
                }
                console.log(fn()());  //4
                console.log(fn()());  //4 */

        /*         function fn(){
                    var a = 3;
                    function fnn(){
                        return ++a;
                    }
                    return fnn;
                }
                var f = fn();
                console.log(f());
                console.log(f()); */

        /*         (function() { 
                    var m = 0; 
                    function getM() { return m; } 
                    function seta(val) { m = val; } 
                    window.g = getM; 
                    window.f = seta; 
                    })(); 
                    f(100);
                    console.info(g());   //100  闭包找到的是同一地址中父级函数中对应变量最终的值 */

        /*         function fn(judge) {
                    function fn1() {
                        console.log(judge);
                    }
                    function fn2() {
                        console.log(judge);
                    }
        
                    switch (judge) {
                        case 1:
                            return fn1;
                            break;
        
                        case 2:
                            return fn2;
                    }
                }
        
                var f = fn(2);
                f(); */

        /*         function demo() {
                    let a = 100;
                    return function () {
                        console.log("i am " + a);
                    }
                }
                let a = 200;
                demo()(); */

        /*         function a() {
                    var i = 0;
                    function b() { console.log(++i); }
                    return b;
                }
                var c = a();
                c();      //1 
                c();      //2  */

        /*         function f() {
                    var count = 0;
                    return function () {
                        count++;
                        console.info(count);
                    }
                }
                var t1 = f();
                t1();     //1 
                t1();     //2 
                t1();     //3 
         */

        /*         var add = function (x) {
                    var sum = 1;
                    var tmp = function (x) {
                        sum = sum + x;
                        return tmp;
                    }
                    tmp.toString = function () {
                        return sum;
                    }
                    return tmp;
                }
                console.log(add(1)(2)(3).toString());     //6 */

        /*         var fn = (function () {
                    var i = 10;
                    function fn() {
                        console.log(++i);
                    }
                    return fn;
                })()
                fn();   //11
                fn();   //12 */

        /*         function fn() {
                    var arr = [];
                    for (var i = 0; i < 5; i++) {
                        arr[i] = function () {
                            return i;
                        }
                    }
                    return arr;
                }
                var list = fn();
                for (var i = 0, len = list.length; i < len; i++) {
                    console.log(list[i]());
                }  //5 5 5 5 5 */

/*         function fn() {
            var arr = [];
            for (var i = 0; i < 5; i++) {
                arr[i] = (function (i) {
                    return function () {
                        return i;
                    };
                })(i);
            }
            return arr;
        }
        var list = fn();
        for (var i = 0, len = list.length; i < len; i++) {
            console.log(list[i]());
        }  //0 1 2 3 4 */


        //测试
        //1
        var name = "window";
        var object = {
            name: "object",
            getNameFunc: function () {
                return function () {
                    return this.name;
                }
            }
        };
        console.log(object.getNameFunc()()); //window
        //obj调用getNameFunc(), 此时this是指向obj, 
        //但是obj.getNamefunc()(), 此时调用的是匿名函数, 等于直接调用, 执行环境具有全局性, this指向window

        var test = object.getNameFunc();
        console.log("test:" + test.call(object));
        //用call使obj调用匿名函数, 此时this指向object

        //2
        var name = "window";
        var object = {
            name: "object",
            getNameFunc: function () {
                var that = this;
                return function () {
                    return that.name;
                }
            }
        };
        console.log(object.getNameFunc()()); //object

        //that保存了this的值, 匿名函数和getname形成闭包, that指向object

        //3
        function fun(n, o) {
            console.log(o);
            return {
                fun: function (m) {
                    return fun(m, n);
                }
            };
        }
        var a = fun(0);
        a.fun(1);
        a.fun(2);
        a.fun(3);
        // undefined 0 0 0
        // a调用的fun是外部函数，形成闭包
        // 所以括号内的参数为m的值，调用时的n为闭包中n的值，即为0
        // 0作为实参传回外部函数fun，o=0，所以都输出0
        // *注意n值的变化

        var b = fun(0).fun(1).fun(2).fun(3);
        // undefined 0 1 2

        var c = fun(0).fun(1);
        c.fun(2);
        c.fun(3);
        // undefined 0 1 1

    </script>

    <!-- 实际应用 -->
    <button>test1</button>
    <button>test2</button>
    <button>test3</button>
    <script>
        var btns = document.getElementsByTagName("button");
        for (var i = 0, length = btns.length; i < length; i++) {
            /* tips：length写在前面性能更好 let可以解决问题 此时用var模拟闭包情况*/

            /*             btns[i].index = i;
                        console.log(btns[i]);
                        btns[i].onclick = function(){
                            alert("I am no." + (this.index + 1));
                        }; */

            (function (i) {
                btns[i].onclick = function () {
                    alert("I am no." + (i + 1));
                };
            })(i);
        }
    </script>
</body>

</html>